package com.sz.biz.logistics.ord.service.impl;

import com.google.common.collect.Lists;
import com.sz.biz.common.constants.CommCodes;
import com.sz.biz.logistics.constants.ErrorCodes;
import com.sz.biz.logistics.ord.dto.OrdSubOrderDto;
import com.sz.biz.logistics.ord.entity.OrdOrderTracking;
import com.sz.biz.logistics.ord.entity.OrdSubOrder;
import com.sz.biz.logistics.ord.entity.OrderStatus;
import com.sz.biz.logistics.ord.service.OrdOrderService;
import com.sz.biz.logistics.ord.service.OrdOrderTrackingService;
import com.sz.biz.logistics.ord.service.OrdSubOrderService;
import com.sz.common.base.dao.ParamData;
import com.sz.common.base.dto.QResultDto;
import com.sz.common.base.dto.QueryParams;
import com.sz.common.base.exception.Exceptions;
import com.sz.common.base.service.AbstractService;
import com.sz.common.base.utils.CollectionUtils;
import com.sz.common.base.utils.EntityUtils;
import com.sz.common.base.utils.StringUtils;
import com.sz.common.core.system.service.SysDictService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.*;

/**
 * Function: 子订单信息 <br>
 * Author: hpeng.wang. <br>
 * Date: 2017-03-31 13:54:00.
 */
@Service("ordSubOrderService")
public class OrdSubOrderServiceImpl extends AbstractService implements OrdSubOrderService {
    @Override
    protected String getMapperNamespace() {
        return "com.sz.biz.logistics.ord.mapper.OrdSubOrderMapper";
    }

    @Autowired
    private SysDictService dictService;
    @Autowired
    private OrdOrderTrackingService ordOrderTrackingService;
    @Autowired
    private OrdOrderService orderService;

    @Override
    public void batchSave(List<OrdSubOrder> ordSubOrderList) {
        if (!CollectionUtils.isEmpty(ordSubOrderList)) {
            dao.batchInsert(getSqlName("insert"), ordSubOrderList);
        }
    }

    @Override
    public void deleteByOrderNo(String orderNo) {
        if (StringUtils.hasLength(orderNo)) {
            dao.delete(getSqlName("deleteByOrderNo"), orderNo);
        }
    }

    @Override
    public OrdSubOrder findBySubOrderNo(String subOrderNo) {
        OrdSubOrder ordSubOrder = null;
        if (StringUtils.hasLength(subOrderNo)) {
            List<OrdSubOrder> subOrderList = findBySubOrderNos(Arrays.asList(subOrderNo));
            if (!CollectionUtils.isEmpty(subOrderList)) {
                ordSubOrder = subOrderList.get(0);
            }
        }
        return ordSubOrder;
    }

    @Override
    public OrdSubOrderDto findDtoBySubOrderNo(String subOrderNo) {
        OrdSubOrderDto subOrderDto = null;
        if (StringUtils.hasLength(subOrderNo)) {
            List<OrdSubOrderDto> subOrderDtoList = findDtoBySubOrderNos(Arrays.asList(subOrderNo));
            if (!CollectionUtils.isEmpty(subOrderDtoList)) {
                subOrderDto = subOrderDtoList.get(0);
            }
        }
        return subOrderDto;
    }

    @Override
    public List<OrdSubOrder> findBySubOrderNos(List<String> subOrderNos) {
        List<OrdSubOrder> subOrderList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(subOrderNos)) {
            ParamData pd = new ParamData();
            pd.put("subOrderNos", subOrderNos);
            subOrderList = dao.findForList(getSqlName("findBySubOrderNos"), pd, OrdSubOrder.class);
        }
        return subOrderList;
    }

    @Override
    public List<OrdSubOrderDto> findDtoBySubOrderNos(List<String> subOrderNos) {
        List<OrdSubOrderDto> subOrderDtoList = new ArrayList<>();
        List<OrdSubOrder> subOrderList = findBySubOrderNos(subOrderNos);
        if (!CollectionUtils.isEmpty(subOrderList)) {
            for (OrdSubOrder subOrder : subOrderList) {
                OrdSubOrderDto subOrderDto = new OrdSubOrderDto();
                EntityUtils.copyPropertiesIgnoreNull(subOrder, subOrderDto);
                subOrderDtoList.add(subOrderDto);
            }

        }
        return subOrderDtoList;
    }

    @Override
    public List<OrdSubOrder> findByOrderNos(List<String> orderNos) {
        List<OrdSubOrder> ordSubOrderList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(orderNos)) {
            ParamData pd = new ParamData();
            pd.put("orderNos", orderNos);
            ordSubOrderList = dao.findForList(getSqlName("findByOrderNos"), pd, OrdSubOrder.class);
        }
        return ordSubOrderList;
    }

    @Override
    public List<OrdSubOrder> findByOrderNo(String orderNo) {
        List<OrdSubOrder> ordSubOrderList = new ArrayList<>();
        if (StringUtils.hasLength(orderNo)) {
            ordSubOrderList = dao.findForList(getSqlName("findByOrderNo"), orderNo, OrdSubOrder.class);
        }
        return ordSubOrderList;
    }

    @Override
    public Map<String, OrdSubOrder> findMapByOrderNo(String orderNo) {
        Map<String, OrdSubOrder> subOrderMap = new HashMap<>();
        List<OrdSubOrder> subOrderList = this.findByOrderNo(orderNo);
        if (!CollectionUtils.isEmpty(subOrderList)) {
            subOrderMap = EntityUtils.getStringKeyMapFromBeans(subOrderList, "subOrderNo");
        }
        return subOrderMap;
    }

    @Override
    public List<OrdSubOrderDto> findDtoByOrderNo(String orderNo) {
        List<OrdSubOrder> subOrderList = this.findByOrderNo(orderNo);
        List<OrdSubOrderDto> subOrderDtoList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(subOrderList)) {
            Map<String, String> sysDictUnitWeightMap = dictService.findMapByCatalog(CommCodes.SYS_DICT_BIZ_UNIT_WEIGHT);
            Map<String, String> sysDictUnitLenghtMap = dictService.findMapByCatalog(CommCodes.SYS_DICT_BIZ_UNIT_LENGHT);
            for (OrdSubOrder subOrder : subOrderList) {
                OrdSubOrderDto subOrderDto = new OrdSubOrderDto();
                EntityUtils.copyPropertiesIgnoreNull(subOrder, subOrderDto);
                subOrderDto.setWeightUnitName(sysDictUnitWeightMap.get(subOrderDto.getWeightUnit()));
                subOrderDto.setLwhUnitName(sysDictUnitLenghtMap.get(subOrderDto.getLwhUnit()));
                subOrderDtoList.add(subOrderDto);
            }
        }
        return subOrderDtoList;
    }

    /**
     * 根据订单号，批量获取子单dto
     *
     * @param orderNos
     * @return
     */
    @Override
    public Map<String, List<OrdSubOrderDto>> findMapDtosByOrderNos(List<String> orderNos) {
        List<OrdSubOrder> ordSubOrderList = findByOrderNos(orderNos);
        Map<String, List<OrdSubOrderDto>> resultMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(ordSubOrderList)) {
            Map<String, String> sysDictUnitWeightMap = dictService.findMapByCatalog(CommCodes.SYS_DICT_BIZ_UNIT_WEIGHT);
            Map<String, String> sysDictUnitLenghtMap = dictService.findMapByCatalog(CommCodes.SYS_DICT_BIZ_UNIT_LENGHT);

            for (OrdSubOrder subOrder : ordSubOrderList) {
                OrdSubOrderDto subOrderDto = new OrdSubOrderDto();
                EntityUtils.copyPropertiesIgnoreNull(subOrder, subOrderDto);
                subOrderDto.setWeightUnitName(sysDictUnitWeightMap.get(subOrderDto.getWeightUnit()));
                subOrderDto.setLwhUnitName(sysDictUnitLenghtMap.get(subOrderDto.getLwhUnit()));

                if (resultMap.containsKey(subOrder.getOrderNo())) {
                    resultMap.get(subOrder.getOrderNo()).add(subOrderDto);
                } else {
                    List<OrdSubOrderDto> dtos = Lists.newArrayList();
                    dtos.add(subOrderDto);
                    resultMap.put(subOrder.getOrderNo(), dtos);
                }

            }
        }
        return resultMap;
    }


    @Override
    public QResultDto findByParam(QueryParams params) {
        return null;
    }

    /**
     * 修改子订单的状态
     *
     * @param subOrderNos
     * @param orderStatus
     * @return
     */

    @Override
    public void updateOrderStatus(List<String> subOrderNos, OrderStatus orderStatus) {
        if (!CollectionUtils.isEmpty(subOrderNos) && !ObjectUtils.isEmpty(orderStatus)) {
            ParamData pd = new ParamData();
            pd.put("subOrderNos", subOrderNos);
            pd.put("orderStatus", orderStatus);
            dao.update(getSqlName("updateOrderStatus"), pd);
        }
    }

    /***
     * 根据订单的编号，更新子订单的状态

     * @param processOrderMap
     */
    @Override
    public void updateOrderStatusByOrderNos(Map<String, OrderStatus> processOrderMap) {
        if (!CollectionUtils.isEmpty(processOrderMap)) {
            List<ParamData> pdList = getParamData(processOrderMap);
            dao.batchUpdate(getSqlName("updateSubOrderStatusByOrderNo"), pdList);
        }
    }

    @Override
    public void updateOrderStatusByOrderNo(String orderNo, OrderStatus orderStatus) {
        Map<String, OrderStatus> orderStatusMap = new HashMap<>();
        orderStatusMap.put(orderNo, orderStatus);
        this.updateOrderStatusByOrderNos(orderStatusMap);
    }

    private List<ParamData> getParamData(Map<String, OrderStatus> processOrderMap) {
        List<ParamData> pdList = new ArrayList<>();
        processOrderMap.forEach((orderNo, orderStatus) -> {
            ParamData pd = new ParamData();
            pd.put("orderNo", orderNo);
            pd.put("orderStatus", orderStatus);
            pdList.add(pd);
        });
        return pdList;
    }

    /**
     * 根据订单的编号从子订单中找到最慢的状态
     *
     * @return
     */
    @Override
    public OrderStatus getMinStatusCodeByOrderNo(String orderNo) {
        OrderStatus orderStatus = null;
        if (!StringUtils.isEmpty(orderNo)) {
            List<OrdSubOrder> subOrderList = this.getMinStatusByOrderNos(Arrays.asList(orderNo));
            if (!CollectionUtils.isEmpty(subOrderList)) {
                String orderStatusCode = subOrderList.get(0).getOrderStatus().getCode();
                orderStatus = OrderStatus.valueOfEnum(orderStatusCode);
            }
        }
        return orderStatus;
    }

    @Override
    public List<OrdSubOrder> getMinStatusByOrderNos(List<String> orderNos) {
        List<OrdSubOrder> subOrderList = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(orderNos)) {
            ParamData pd = new ParamData();
            pd.put("orderNos", orderNos);
            subOrderList = dao.findForList(getSqlName("getMinStatusByOrderNos"), pd, OrdSubOrder.class);
        }
        return subOrderList;
    }

    @Override
    public OrdSubOrder getMinStatusByOrderNo(String orderNo) {
        OrdSubOrder subOrder = null;
        if (!StringUtils.isEmpty(orderNo)) {
            List<OrdSubOrder> subOrderList = this.getMinStatusByOrderNos(Arrays.asList(orderNo));
            if (!CollectionUtils.isEmpty(subOrderList)) {
                subOrder = subOrderList.get(0);
            }
        }
        return subOrder;
    }

    @Override
    public List<String> getSubOrdNos(String orderNo) {
        ParamData pd = new ParamData();
        pd.put("orderNo", orderNo);
        List<String> subOrdNos = dao.findForList(getSqlName("getSubOrdNos"), pd, String.class);
        return subOrdNos;
    }


    /**
     * 更新子单
     *
     * @param subOrder
     * @return
     */
    @Override
    public void update(OrdSubOrder subOrder) {
        if (!ObjectUtils.isEmpty(subOrder)) {
            this.batchUpdate(Arrays.asList(subOrder));
        }
    }

    @Override
    public void batchUpdate(List<OrdSubOrder> subOrderList) {
        if (!CollectionUtils.isEmpty(subOrderList)) {
            dao.batchUpdate(getSqlName("updateBySubOrderNoSelective"), subOrderList);
        }
    }

    /**
     * 订单提交时，批量增加子单的物理信息
     * 1.当订单提交时， 需要加入code为201， 202的物流信息。
     * 2.当订单为已受理时，需要加入203，的物流信息。
     *
     * @param orderNo
     * @param waybillNo
     * @param orderStatus
     * @param subOrderNos
     */
    @Override
    public void batchAddSubTracking(String orderNo, String waybillNo, OrderStatus orderStatus, List<String> subOrderNos) {
        if (!ObjectUtils.isEmpty(orderNo) && !CollectionUtils.isEmpty(subOrderNos)) {
            List<OrdOrderTracking> trackingList = getOrdOrderTrackings(orderNo, waybillNo, orderStatus, subOrderNos);
            ordOrderTrackingService.batchSave(trackingList);
        }
    }

    @Override
    public List<OrdOrderTracking> batchAddSubTrackings(String orderNo, String waybillNo, OrderStatus orderStatus, List<String> subOrderNos) {
        List<OrdOrderTracking> trackingList = new ArrayList<>();
        if (!ObjectUtils.isEmpty(orderNo) && !CollectionUtils.isEmpty(subOrderNos)) {
            trackingList = getOrdOrderTrackings(orderNo, waybillNo, orderStatus, subOrderNos);
        }
        return trackingList;
    }

    private List<OrdOrderTracking> getOrdOrderTrackings(String orderNo, String waybillNo, OrderStatus orderStatus, List<String> subOrderNos) {
        List<String> codeList = Lists.newArrayList();

        if (orderStatus == OrderStatus.COMMITED) {
            codeList.addAll(Arrays.asList(CommCodes.TRACKING_CODE_WAIT_PENDING, CommCodes.TRACKING_CODE_WAIT_ACCEPT));//下单成功，等待系统确认
        } else if (orderStatus == OrderStatus.ACCEPT) {
            codeList.addAll(Arrays.asList(CommCodes.TRACKING_CODE_WAIT_PENDING, CommCodes.TRACKING_CODE_WAIT_ACCEPT));//下单成功，等待系统确认
            codeList.addAll(Arrays.asList(CommCodes.TRACKING_CODE_WAIT_RECEGOOD));//下单成功，等待系统确认
        }
        return this.processOrderTracking(orderNo, waybillNo, subOrderNos, codeList);
    }

    @Override
    public List<OrdOrderTracking> processOrderTracking(String orderNo, String waybillNo, List<String> subOrderNoList, List<String> codeList) {
        List<OrdOrderTracking> trackingList = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(codeList) && !CollectionUtils.isEmpty(subOrderNoList) && StringUtils.hasLength(orderNo)) {
            subOrderNoList.forEach(subOrderNo -> {
                codeList.forEach(code -> {
                    OrdOrderTracking tracking = new OrdOrderTracking();
                    tracking.setOrderNo(orderNo);
                    tracking.setWaybillNo(waybillNo);
                    tracking.setSubOrderNo(subOrderNo);
                    tracking.setOriginalId(0);
                    tracking.setCode(code);
                    tracking.setType(CommCodes.TRACKING_TYPE_SYSTEM_AUTO);
                    tracking.setStatus(CommCodes.TRACKING_STATUS_FINISH);
                    trackingList.add(tracking);
                });
            });
        }
        return trackingList;
    }

    @Override
    public Map<String, List<String>> findMapByOrderNos(List<String> orderNoList) {
        Map<String, List<String>> subOrderNoMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(orderNoList)) {
            List<OrdSubOrder> subOrderList = this.findByOrderNos(orderNoList);
            for (OrdSubOrder subOrder : subOrderList) {
                if (subOrderNoMap.get(subOrder.getOrderNo()) == null) {
                    List<String> subOrderNoList = new ArrayList<>();
                    subOrderNoMap.put(subOrder.getOrderNo(), subOrderNoList);
                }
                subOrderNoMap.get(subOrder.getOrderNo()).add(subOrder.getSubOrderNo());
            }
        }
        return subOrderNoMap;
    }

    @Override
    public List<String> findSubOrderNoByOrderNo(String orderNo) {
        List<String> subOrderNoList = new ArrayList<>();
        Map<String, List<String>> map = this.findMapByOrderNos(Arrays.asList(orderNo));
        if (!CollectionUtils.isEmpty(map)) {
            subOrderNoList = map.get(orderNo);
        }
        return subOrderNoList;
    }

    private String findWaybillBySubOrderNo(String subOrderNo) {
        String orderNo = null;
        OrdSubOrder subOrder = this.findBySubOrderNo(subOrderNo);
        if (!ObjectUtils.isEmpty(subOrder)) {
            orderNo = subOrder.getOrderNo();
        }
        return orderNo;
    }

    @Override
    public int checkSubOrOrderNo(int type, String number) {
        int count = 0;
        if (StringUtils.hasLength(number) && type > 0) {
            this.checkOrderStatusGTCommited(type, number);//如果订单状态小于已受理状态，不允许添加物流信息

            ParamData pd = new ParamData();
            pd.put("type", type);
            pd.put("number", number);
            count = (int) dao.findForObject(getSqlName("getCountBySubOrOrderNo"), pd);
        }
        return count;
    }

    private void checkOrderStatusGTCommited(int type, String number) {
        String orderNo = null;

        switch (type) {
            case CommCodes.ORD_TRACKING_SEARCH_TYPE_WAYBILLNO://根据orderNo
                orderNo = number;
                break;
            case CommCodes.ORD_TRACKING_SEARCH_TYPE_SUBWAYBILLNO://根据subOrderNo
                orderNo = this.findWaybillBySubOrderNo(number);
                break;
            default:
                break;
        }
        if (StringUtils.hasLength(orderNo)) {
            OrderStatus orderStatus = orderService.findOrderStatus(orderNo);
            if (!ObjectUtils.isEmpty(orderStatus) && OrderStatus.DRAFT.equals(orderStatus)) {
                throw Exceptions.bizException(ErrorCodes.ERROR_WAYBILLNO_EQ_DRAFT);
            }
        }
    }


    @Override
    public void updateOrderNoByOrderNo(String oldOrderNo, String newOrderNo) {
        if (StringUtils.isEmpty(oldOrderNo) || StringUtils.isEmpty(newOrderNo)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "提交订单异常");
        }
        ParamData pd = new ParamData();
        pd.put("newOrderNo", newOrderNo);
        pd.put("oldOrderNo", oldOrderNo);
        dao.update(getSqlName("updateOrderNoByOrderNo"), pd);
    }

    @Override
    public void updateOrderStatus(Map<String, OrderStatus> updateSubOrderNoMap) {
        if (!CollectionUtils.isEmpty(updateSubOrderNoMap)) {
            List<ParamData> pdList = new ArrayList<>();
            updateSubOrderNoMap.forEach((subOrderNo, orderStatus) -> {
                ParamData pd = new ParamData();
                pd.put("subOrderNo", subOrderNo);
                pd.put("orderStatus", orderStatus);
                pdList.add(pd);
            });
            dao.batchUpdate(getSqlName("updateOrderStatusBySubOrderNo"), pdList);
        }


    }

    @Override
    public Map<String, String> findWaybillNoOrderNoMapBySubOrders(List<String> subOrderNos) {
        Map<String, String> map = new HashMap<>();
        if (!CollectionUtils.isEmpty(subOrderNos)) {
            List<Map> list = dao.findForList(getSqlName("findWaybillNoOrderNoMapBySubOrders"), subOrderNos, Map.class);

            if (!CollectionUtils.isEmpty(list)) {
                for (Map m : list) {
                    String orderNo = (String) m.get("orderNo");
                    String waybillNo = (String) m.get("waybillNo");
                    map.put(orderNo, waybillNo);
                }
            }
        }
        return map;
    }


    /**
     * 根据packageNum保存子单。
     *
     * @param orderNo
     * @param waybillNo   订单号
     * @param packageNum  子单个数
     * @param orderStatus 子单状态
     * @return 生成的子单编号
     */
    @Override
    public List<String> saveSubOrders(String orderNo, String waybillNo, int packageNum, OrderStatus orderStatus) {
        this.deleteByOrderNo(orderNo);
        //1 保存子订单,长宽高此时没有数据
        List<OrdSubOrder> subOrderList = Lists.newArrayList();
        List<String> subOrderNos = generateSubOrderNo(waybillNo, packageNum);
        for (int i = 0; i < packageNum; i++) {
            OrdSubOrder subOrder = new OrdSubOrder();
            subOrder.setOrderNo(orderNo);
            subOrder.setSubOrderNo(subOrderNos.get(i));
            subOrder.setOrderStatus(orderStatus);
            subOrderList.add(subOrder);
        }
        this.batchSave(subOrderList);
        return subOrderNos;
    }

    @Override
    public List<String> generateSubOrderNo(String waybillNo, int packageNum) {
        if (packageNum <= 0) {
            return null;
        }
        List<String> subOrderNos = Lists.newArrayList();
        String subOrderNoSuffix;
        for (int i = 0; i < packageNum; i++) {
            if (packageNum == 1) {
                subOrderNoSuffix = String.format("%03d", i);
            } else {
                subOrderNoSuffix = String.format("%03d", i + 1);
            }
            String suberOrderNo = waybillNo + subOrderNoSuffix;
            subOrderNos.add(suberOrderNo);
        }
        return subOrderNos;
    }


}
